library(data.table)
library(viridis)
Loading required package: viridisLite
library(ggplot2)
library(reshape2)

Attaching package: ‘reshape2’

The following objects are masked from ‘package:data.table’:

    dcast, melt
library(geosphere)
library(vegan)
library(raster)
Loading required package: sp

Attaching package: ‘raster’

The following object is masked from ‘package:data.table’:

    shift
#load spring and fall data
dat_NEUS_grid.spring.reduced_3plustows <- readRDS("/Users/zoekitchel/Documents/grad school/Rutgers/Repositories/trawl_spatial_turnover/data/gridded/USA-NEUS/dat_NEUS_grid.spring.reduced_3plustows.RData")

dat_NEUS_grid.fall.reduced_3plustows <- readRDS("/Users/zoekitchel/Documents/grad school/Rutgers/Repositories/trawl_spatial_turnover/data/gridded/USA-NEUS/dat_NEUS_grid.fall.reduced_3plustows.RData")

#distance among grid cells
neus_reg_distances_fall.l <- readRDS("/Users/zoekitchel/Documents/grad school/Rutgers/Repositories/trawl_spatial_turnover/data/gridded/USA-NEUS/neus_reg_distances_fall.l.RData")

neus_reg_distances_spring.l <- readRDS("/Users/zoekitchel/Documents/grad school/Rutgers/Repositories/trawl_spatial_turnover/data/gridded/USA-NEUS/neus_reg_distances_spring.l.RData")

Lists of Years

#spring
dat_NEUS_grid.spring.reduced_3plustows[,year:= as.numeric(year)] #make numeric
setorder(dat_NEUS_grid.spring.reduced_3plustows, year)

neus_years_spring <- unique(dat_NEUS_grid.spring.reduced_3plustows[,year])

#fall
dat_NEUS_grid.fall.reduced_3plustows[,year:= as.numeric(year)] #make numeric
setorder(dat_NEUS_grid.fall.reduced_3plustows, year)

neus_years_fall <- unique(dat_NEUS_grid.fall.reduced_3plustows[,year])

Haul ID keys

neus_spring_haulids <- unique(dat_NEUS_grid.spring.reduced_3plustows[,haulid])
neus_spring_haulids_key <- data.table(haulid = neus_spring_haulids, key_ID = seq(1,length(neus_spring_haulids), by = 1))

neus_fall_haulids <- unique(dat_NEUS_grid.fall.reduced_3plustows[,haulid])
neus_fall_haulids_key <- data.table(haulid = neus_fall_haulids, key_ID = seq(1,length(neus_fall_haulids), by = 1))

Convert haulids to numeric key_IDs

#spring
dat_NEUS_grid.spring.reduced_3plustows <- dat_NEUS_grid.spring.reduced_3plustows[neus_spring_haulids_key, on = "haulid"]

#fall
dat_NEUS_grid.fall.reduced_3plustows <- dat_NEUS_grid.fall.reduced_3plustows[neus_fall_haulids_key, on = "haulid"]

Dissimilarities across multiple years SPRING

neus_spring_distances_dissimilarities_allyears <- data.table("haulid1" = integer(), "haulid2" = integer(), "distance" = numeric(),"bray_curtis_dissimilarity" = numeric(), year = integer(), "jaccard_dissimilarity" = numeric())

#Now loop through all years
for (i in 1:length(neus_years_spring)) {
  reduced_year <- dat_NEUS_grid.spring.reduced_3plustows[year == neus_years_spring[i],]
  
  #distances among cells
  setorder(reduced_year, key_ID)
  
  lat_lon_haulid <- unique(reduced_year[,.(lat,lon,key_ID)])
  neus_distances <- distm(lat_lon_haulid[,.(lon,lat)])
  key_IDs <- lat_lon_haulid[,key_ID]

  colnames(neus_distances) <- rownames(neus_distances) <- key_IDs

  #wide to long
  haulid_distances.l <- reshape2::melt(neus_distances,varnames = (c("haulid1", "haulid2")), value.name = "distance")
  
  #make into data table
  haulid_distances.l <- data.table(haulid_distances.l)

  
  reduced_year_wide <- dcast(reduced_year, key_ID + year ~ matched_name2, value.var = "wtcpue", fun.aggregate = sum) #long to wide data for community matrix, column names are cell then species
  
  ncols <- ncol(reduced_year_wide)
  communitymatrix <- cbind(reduced_year_wide[,3:ncols], reduced_year_wide[,1:2]) #community matrix with year and cell on far right

  #list of haulid keys
  key_IDs_subset <- communitymatrix$key_ID

  dissimilarities_abundance <- vegdist(communitymatrix[,1:(ncols-2)], method = "bray", binary = F) #dissimilarity 
  dissimilarities_occurrence <- vegdist(communitymatrix[,1:(ncols-2)], method = "jaccard", binary = T) #T binary performs presence absence standardization before using decostand

  #make into matrix
  dissimilarities_abundance.m <- as.matrix(dissimilarities_abundance, labels=TRUE)
  dissimilarities_occurrence.m <- as.matrix(dissimilarities_occurrence, labels=TRUE)
  colnames(dissimilarities_abundance.m) <- rownames(dissimilarities_abundance.m) <- key_IDs_subset
  colnames(dissimilarities_occurrence.m) <- rownames(dissimilarities_occurrence.m) <- key_IDs_subset

  #reshape dissimilarities
  dissimilarities_abundance.l <- reshape2::melt(dissimilarities_abundance.m, varnames = c("haulid1", "haulid2"), value.name = "bray_curtis_dissimilarity")
  dissimilarities_occurrence.l <- reshape2::melt(dissimilarities_occurrence.m, varnames = c("haulid1", "haulid2"), value.name = "jaccard_dissimilarity")
  dissimilarities_abundance.l <- data.table(dissimilarities_abundance.l) #and then to data table
  dissimilarities_occurrence.l <- data.table(dissimilarities_occurrence.l)

  #add year for these values
  dissimilarities_abundance.l[, "year" := neus_years_spring[i]]
  dissimilarities_occurrence.l[, "year" := neus_years_spring[i]]

  #merge distance with dissimilarity for this year with both metrics of dissimilarity
  dissimilarities_full <- haulid_distances.l[dissimilarities_abundance.l, on = c("haulid1", "haulid2")]
  dissimilarities_full <- dissimilarities_full[dissimilarities_occurrence.l, on = c("haulid1", "haulid2", "year")]


  #add to data table
  neus_spring_distances_dissimilarities_allyears <- rbind(neus_spring_distances_dissimilarities_allyears, dissimilarities_full)
  
}
you have empty rows: their dissimilarities may be meaningless in method “bray”you have empty rows: their dissimilarities may be meaningless in method “jaccard”you have empty rows: their dissimilarities may be meaningless in method “bray”you have empty rows: their dissimilarities may be meaningless in method “jaccard”
summary(neus_spring_distances_dissimilarities_allyears) #here we have bray, jaccard and geographic distance
    haulid1         haulid2         distance       bray_curtis_dissimilarity      year     
 Min.   :    1   Min.   :    1   Min.   :      0   Min.   :0.0000            Min.   :1973  
 1st Qu.: 2765   1st Qu.: 2765   1st Qu.: 187365   1st Qu.:0.8404            1st Qu.:1984  
 Median : 6050   Median : 6050   Median : 330150   Median :0.9499            Median :1998  
 Mean   : 5949   Mean   : 5949   Mean   : 385001   Mean   :0.8818            Mean   :1997  
 3rd Qu.: 9137   3rd Qu.: 9137   3rd Qu.: 554298   3rd Qu.:0.9910            3rd Qu.:2010  
 Max.   :11686   Max.   :11686   Max.   :1206210   Max.   :1.0000            Max.   :2019  
 jaccard_dissimilarity
 Min.   :0.0000       
 1st Qu.:0.7059       
 Median :0.8214       
 Mean   :0.7924       
 3rd Qu.:0.9091       
 Max.   :1.0000       
#delete repeats
neus_spring_distances_dissimilarities_allyears <- neus_spring_distances_dissimilarities_allyears[haulid1 >= haulid2,] #3165272 to 1588479 rows


neus_spring_distances_dissimilarities_allyears[,bray_curtis_similarity := (1-bray_curtis_dissimilarity)][,jaccard_similarity := (1-jaccard_dissimilarity)]

saveRDS(neus_spring_distances_dissimilarities_allyears, file = "neus_spring_distances_dissimilarities_allyears.rds")

#Heat map

Subsample for plotting

#jaccard only
neus_spring_distances_dissimilarities_allyears_jaccard <- neus_spring_distances_dissimilarities_allyears[,.(year,distance,jaccard_similarity)]

#new column with rounded distance
neus_spring_distances_dissimilarities_allyears_jaccard[,distance_10s := round(distance,-1)] #round to nearest 100

#new column with median jaccard similarity
neus_spring_distances_dissimilarities_allyears_jaccard[, jaccard_similarity_mean := mean(jaccard_similarity), .(year, distance_10s)]

#reduce to unique values
neus_spring_distances_dissimilarities_allyears_jaccard_rounded <- unique(neus_spring_distances_dissimilarities_allyears_jaccard, by = c("year","distance_10s"))

All possible combos

#combine
neus_spring_distances_dissimilarities_allyears_jaccard_rounded_allcombos <- neus_spring_distances_dissimilarities_allyears_jaccard_allcombos[neus_spring_distances_dissimilarities_allyears_jaccard_rounded, by = c("year","distance_10s")]
Ignoring by= because j= is not suppliedError in `[.data.table`(neus_spring_distances_dissimilarities_allyears_jaccard_allcombos,  : 
  When i is a data.table (or character vector), the columns to join by must be specified using 'on=' argument (see ?data.table), by keying x (i.e. sorted, and, marked as sorted, see ?setkey), or by sharing column names between x and i (i.e., a natural join). Keyed joins might have further speed benefits on very large data due to x being sorted in RAM.

Trying to use ggplot

Convert to matrix

Convert comprehensive table to matrix

neus_spring_distances_dissimilarities_allyears_jaccard_rounded_allcombos_wide <- data.table::dcast(neus_spring_distances_dissimilarities_allyears_jaccard_rounded_allcombos[,.(year,distance_10s,jaccard_similarity_mean)], distance_10s ~ year, fill = NA)
Using 'jaccard_similarity_mean' as value column. Use 'value.var' to override
neus_spring_distances_dissimilarities_allyears_jaccard_rounded_allcombos_wide <- data.table::dcast(neus_spring_distances_dissimilarities_allyears_jaccard_rounded_allcombos[,.(year,distance_10s,jaccard_similarity_mean)], distance_10s ~ year, fill = NA)
Using 'jaccard_similarity_mean' as value column. Use 'value.var' to override
setkey(neus_spring_distances_dissimilarities_allyears_jaccard_rounded_allcombos_wide, distance_10s)
#get rid of first column
neus_spring_distances_dissimilarities_allyears_jaccard_rounded_allcombos_wide.m <- neus_spring_distances_dissimilarities_allyears_jaccard_rounded_allcombos_wide[,2:ncol(neus_spring_distances_dissimilarities_allyears_jaccard_rounded_allcombos_wide)]
#get rid of first column
neus_spring_distances_dissimilarities_allyears_jaccard_rounded_allcombos_wide.m <- neus_spring_distances_dissimilarities_allyears_jaccard_rounded_allcombos_wide[,2:ncol(neus_spring_distances_dissimilarities_allyears_jaccard_rounded_allcombos_wide)]
neus_spring_distances_dissimilarities_allyears_jaccard_rounded_allcombos_wide.m <- as.matrix(neus_spring_distances_dissimilarities_allyears_jaccard_rounded_allcombos_wide.m)
neus_spring_distances_dissimilarities_allyears_jaccard_rounded_allcombos_wide.r <- as.raster (neus_spring_distances_dissimilarities_allyears_jaccard_rounded_allcombos_wide.m)

Plot raster

image(neus_spring_distances_dissimilarities_allyears_jaccard_rounded_allcombos_wide.r)
Error in image.default(neus_spring_distances_dissimilarities_allyears_jaccard_rounded_allcombos_wide.r) : 
  'z' must be numeric or logical

From “Depth-Time visualization using R, the tidyverse, and ggplot2” tutorial

Box plots

###maybe i’ll do this later? maybe not At its heart, this graphic is just a ggplot() with a geom_raster() layer. The complication is, geom_raster() requires equally spaced points in both the x- and y-direction. The rest of this post is about how to make that happen.

Linear Interpolation

I interpolate in the distance direction first, because I think this is the better assumption: as you go down further away, a reasonable way to estimate the similarity at a distance which you did not measure is to draw a straight line between the similarity at the distance that you did measure. (Not great, but sure)

estimate_jac_sim_by_year(1990, c(0,3000,300000))
collapsing to unique 'x' values
[1] 1.0000000 0.5103346 0.3037503

Expand data inputs

Visualize

First, we write a function that estimates the temperature at any date given a depth that is in temp_interp_depth (the tibble we just calculated).

estimate_jac_sim_by_distance(
  target_distance = 1000000, 
  target_year = c(1990,1998,2000)
)
[1] 0.12801222 0.06626988 0.06779441

Expand year grid

jac_sim_raster[,jaccard_similarity_modeled := estimate_jac_sim_by_distance(distance,year),by = distance]
Error in approx(data_for_distance$year, data_for_distance$jaccard_similarity_modeled,  : 
  need at least two non-NA values to interpolate

Finally, we have equally-spaced values in both the date and depth dimensions. This can be visualized using geom_raster(), with temp mapped to the fill aesthetic. I’ve again used scale_fill_gradient2() to ensure that red values represent “hot”, blue values represent “cool”, and that there is some way to visualize the depth of the thermocline. Finally, I’ve used coord_cartesian(expand = FALSE) to eliminate the white border around the outside of the raster layer…I think it looks nicer that way.

LS0tCnRpdGxlOiAiTkVVU19zaW1pbGFyaXR5X2hlYXRtYXBfZGlzdGFuY2UiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCmBgYHtyIHNldHVwfQpsaWJyYXJ5KGRhdGEudGFibGUpCmxpYnJhcnkodmlyaWRpcykKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHJlc2hhcGUyKQpsaWJyYXJ5KGdlb3NwaGVyZSkKbGlicmFyeSh2ZWdhbikKbGlicmFyeShyYXN0ZXIpCgojbG9hZCBzcHJpbmcgYW5kIGZhbGwgZGF0YQpkYXRfTkVVU19ncmlkLnNwcmluZy5yZWR1Y2VkXzNwbHVzdG93cyA8LSByZWFkUkRTKCIvVXNlcnMvem9la2l0Y2hlbC9Eb2N1bWVudHMvZ3JhZCBzY2hvb2wvUnV0Z2Vycy9SZXBvc2l0b3JpZXMvdHJhd2xfc3BhdGlhbF90dXJub3Zlci9kYXRhL2dyaWRkZWQvVVNBLU5FVVMvZGF0X05FVVNfZ3JpZC5zcHJpbmcucmVkdWNlZF8zcGx1c3Rvd3MuUkRhdGEiKQoKZGF0X05FVVNfZ3JpZC5mYWxsLnJlZHVjZWRfM3BsdXN0b3dzIDwtIHJlYWRSRFMoIi9Vc2Vycy96b2VraXRjaGVsL0RvY3VtZW50cy9ncmFkIHNjaG9vbC9SdXRnZXJzL1JlcG9zaXRvcmllcy90cmF3bF9zcGF0aWFsX3R1cm5vdmVyL2RhdGEvZ3JpZGRlZC9VU0EtTkVVUy9kYXRfTkVVU19ncmlkLmZhbGwucmVkdWNlZF8zcGx1c3Rvd3MuUkRhdGEiKQoKI2Rpc3RhbmNlIGFtb25nIGdyaWQgY2VsbHMKbmV1c19yZWdfZGlzdGFuY2VzX2ZhbGwubCA8LSByZWFkUkRTKCIvVXNlcnMvem9la2l0Y2hlbC9Eb2N1bWVudHMvZ3JhZCBzY2hvb2wvUnV0Z2Vycy9SZXBvc2l0b3JpZXMvdHJhd2xfc3BhdGlhbF90dXJub3Zlci9kYXRhL2dyaWRkZWQvVVNBLU5FVVMvbmV1c19yZWdfZGlzdGFuY2VzX2ZhbGwubC5SRGF0YSIpCgpuZXVzX3JlZ19kaXN0YW5jZXNfc3ByaW5nLmwgPC0gcmVhZFJEUygiL1VzZXJzL3pvZWtpdGNoZWwvRG9jdW1lbnRzL2dyYWQgc2Nob29sL1J1dGdlcnMvUmVwb3NpdG9yaWVzL3RyYXdsX3NwYXRpYWxfdHVybm92ZXIvZGF0YS9ncmlkZGVkL1VTQS1ORVVTL25ldXNfcmVnX2Rpc3RhbmNlc19zcHJpbmcubC5SRGF0YSIpCmBgYApMaXN0cyBvZiBZZWFycwpgYGB7ciB5ZWFyIGxpc3RzfQojc3ByaW5nCmRhdF9ORVVTX2dyaWQuc3ByaW5nLnJlZHVjZWRfM3BsdXN0b3dzWyx5ZWFyOj0gYXMubnVtZXJpYyh5ZWFyKV0gI21ha2UgbnVtZXJpYwpzZXRvcmRlcihkYXRfTkVVU19ncmlkLnNwcmluZy5yZWR1Y2VkXzNwbHVzdG93cywgeWVhcikKCm5ldXNfeWVhcnNfc3ByaW5nIDwtIHVuaXF1ZShkYXRfTkVVU19ncmlkLnNwcmluZy5yZWR1Y2VkXzNwbHVzdG93c1sseWVhcl0pCgojZmFsbApkYXRfTkVVU19ncmlkLmZhbGwucmVkdWNlZF8zcGx1c3Rvd3NbLHllYXI6PSBhcy5udW1lcmljKHllYXIpXSAjbWFrZSBudW1lcmljCnNldG9yZGVyKGRhdF9ORVVTX2dyaWQuZmFsbC5yZWR1Y2VkXzNwbHVzdG93cywgeWVhcikKCm5ldXNfeWVhcnNfZmFsbCA8LSB1bmlxdWUoZGF0X05FVVNfZ3JpZC5mYWxsLnJlZHVjZWRfM3BsdXN0b3dzWyx5ZWFyXSkKYGBgCgpIYXVsIElEIGtleXMKYGBge3IgbGlzdCBvZiBoYXVsaWRzfQpuZXVzX3NwcmluZ19oYXVsaWRzIDwtIHVuaXF1ZShkYXRfTkVVU19ncmlkLnNwcmluZy5yZWR1Y2VkXzNwbHVzdG93c1ssaGF1bGlkXSkKbmV1c19zcHJpbmdfaGF1bGlkc19rZXkgPC0gZGF0YS50YWJsZShoYXVsaWQgPSBuZXVzX3NwcmluZ19oYXVsaWRzLCBrZXlfSUQgPSBzZXEoMSxsZW5ndGgobmV1c19zcHJpbmdfaGF1bGlkcyksIGJ5ID0gMSkpCgpuZXVzX2ZhbGxfaGF1bGlkcyA8LSB1bmlxdWUoZGF0X05FVVNfZ3JpZC5mYWxsLnJlZHVjZWRfM3BsdXN0b3dzWyxoYXVsaWRdKQpuZXVzX2ZhbGxfaGF1bGlkc19rZXkgPC0gZGF0YS50YWJsZShoYXVsaWQgPSBuZXVzX2ZhbGxfaGF1bGlkcywga2V5X0lEID0gc2VxKDEsbGVuZ3RoKG5ldXNfZmFsbF9oYXVsaWRzKSwgYnkgPSAxKSkKYGBgCgpDb252ZXJ0IGhhdWxpZHMgdG8gbnVtZXJpYyBrZXlfSURzCmBgYHtyfQojc3ByaW5nCmRhdF9ORVVTX2dyaWQuc3ByaW5nLnJlZHVjZWRfM3BsdXN0b3dzIDwtIGRhdF9ORVVTX2dyaWQuc3ByaW5nLnJlZHVjZWRfM3BsdXN0b3dzW25ldXNfc3ByaW5nX2hhdWxpZHNfa2V5LCBvbiA9ICJoYXVsaWQiXQoKI2ZhbGwKZGF0X05FVVNfZ3JpZC5mYWxsLnJlZHVjZWRfM3BsdXN0b3dzIDwtIGRhdF9ORVVTX2dyaWQuZmFsbC5yZWR1Y2VkXzNwbHVzdG93c1tuZXVzX2ZhbGxfaGF1bGlkc19rZXksIG9uID0gImhhdWxpZCJdCmBgYAoKCkRpc3NpbWlsYXJpdGllcyBhY3Jvc3MgbXVsdGlwbGUgeWVhcnMKU1BSSU5HCmBgYHtyIGRpc3NpbWlsYXJpdGllcyBiZXR3ZWVuIGNlbGxzIGFjcm9zcyBtdWx0aXBsZSB5ZWFycyBmb3Igc3ByaW5nfQpuZXVzX3NwcmluZ19kaXN0YW5jZXNfZGlzc2ltaWxhcml0aWVzX2FsbHllYXJzIDwtIGRhdGEudGFibGUoImhhdWxpZDEiID0gaW50ZWdlcigpLCAiaGF1bGlkMiIgPSBpbnRlZ2VyKCksICJkaXN0YW5jZSIgPSBudW1lcmljKCksImJyYXlfY3VydGlzX2Rpc3NpbWlsYXJpdHkiID0gbnVtZXJpYygpLCB5ZWFyID0gaW50ZWdlcigpLCAiamFjY2FyZF9kaXNzaW1pbGFyaXR5IiA9IG51bWVyaWMoKSkKCiNOb3cgbG9vcCB0aHJvdWdoIGFsbCB5ZWFycwpmb3IgKGkgaW4gMTpsZW5ndGgobmV1c195ZWFyc19zcHJpbmcpKSB7CiAgcmVkdWNlZF95ZWFyIDwtIGRhdF9ORVVTX2dyaWQuc3ByaW5nLnJlZHVjZWRfM3BsdXN0b3dzW3llYXIgPT0gbmV1c195ZWFyc19zcHJpbmdbaV0sXQogIAogICNkaXN0YW5jZXMgYW1vbmcgY2VsbHMKICBzZXRvcmRlcihyZWR1Y2VkX3llYXIsIGtleV9JRCkKICAKICBsYXRfbG9uX2hhdWxpZCA8LSB1bmlxdWUocmVkdWNlZF95ZWFyWywuKGxhdCxsb24sa2V5X0lEKV0pCiAgbmV1c19kaXN0YW5jZXMgPC0gZGlzdG0obGF0X2xvbl9oYXVsaWRbLC4obG9uLGxhdCldKQogIGtleV9JRHMgPC0gbGF0X2xvbl9oYXVsaWRbLGtleV9JRF0KCiAgY29sbmFtZXMobmV1c19kaXN0YW5jZXMpIDwtIHJvd25hbWVzKG5ldXNfZGlzdGFuY2VzKSA8LSBrZXlfSURzCgogICN3aWRlIHRvIGxvbmcKICBoYXVsaWRfZGlzdGFuY2VzLmwgPC0gcmVzaGFwZTI6Om1lbHQobmV1c19kaXN0YW5jZXMsdmFybmFtZXMgPSAoYygiaGF1bGlkMSIsICJoYXVsaWQyIikpLCB2YWx1ZS5uYW1lID0gImRpc3RhbmNlIikKICAKICAjbWFrZSBpbnRvIGRhdGEgdGFibGUKICBoYXVsaWRfZGlzdGFuY2VzLmwgPC0gZGF0YS50YWJsZShoYXVsaWRfZGlzdGFuY2VzLmwpCgogIAogIHJlZHVjZWRfeWVhcl93aWRlIDwtIGRjYXN0KHJlZHVjZWRfeWVhciwga2V5X0lEICsgeWVhciB+IG1hdGNoZWRfbmFtZTIsIHZhbHVlLnZhciA9ICJ3dGNwdWUiLCBmdW4uYWdncmVnYXRlID0gc3VtKSAjbG9uZyB0byB3aWRlIGRhdGEgZm9yIGNvbW11bml0eSBtYXRyaXgsIGNvbHVtbiBuYW1lcyBhcmUgY2VsbCB0aGVuIHNwZWNpZXMKICAKICBuY29scyA8LSBuY29sKHJlZHVjZWRfeWVhcl93aWRlKQogIGNvbW11bml0eW1hdHJpeCA8LSBjYmluZChyZWR1Y2VkX3llYXJfd2lkZVssMzpuY29sc10sIHJlZHVjZWRfeWVhcl93aWRlWywxOjJdKSAjY29tbXVuaXR5IG1hdHJpeCB3aXRoIHllYXIgYW5kIGNlbGwgb24gZmFyIHJpZ2h0CgogICNsaXN0IG9mIGhhdWxpZCBrZXlzCiAga2V5X0lEc19zdWJzZXQgPC0gY29tbXVuaXR5bWF0cml4JGtleV9JRAoKICBkaXNzaW1pbGFyaXRpZXNfYWJ1bmRhbmNlIDwtIHZlZ2Rpc3QoY29tbXVuaXR5bWF0cml4WywxOihuY29scy0yKV0sIG1ldGhvZCA9ICJicmF5IiwgYmluYXJ5ID0gRikgI2Rpc3NpbWlsYXJpdHkgCiAgZGlzc2ltaWxhcml0aWVzX29jY3VycmVuY2UgPC0gdmVnZGlzdChjb21tdW5pdHltYXRyaXhbLDE6KG5jb2xzLTIpXSwgbWV0aG9kID0gImphY2NhcmQiLCBiaW5hcnkgPSBUKSAjVCBiaW5hcnkgcGVyZm9ybXMgcHJlc2VuY2UgYWJzZW5jZSBzdGFuZGFyZGl6YXRpb24gYmVmb3JlIHVzaW5nIGRlY29zdGFuZAoKICAjbWFrZSBpbnRvIG1hdHJpeAogIGRpc3NpbWlsYXJpdGllc19hYnVuZGFuY2UubSA8LSBhcy5tYXRyaXgoZGlzc2ltaWxhcml0aWVzX2FidW5kYW5jZSwgbGFiZWxzPVRSVUUpCiAgZGlzc2ltaWxhcml0aWVzX29jY3VycmVuY2UubSA8LSBhcy5tYXRyaXgoZGlzc2ltaWxhcml0aWVzX29jY3VycmVuY2UsIGxhYmVscz1UUlVFKQogIGNvbG5hbWVzKGRpc3NpbWlsYXJpdGllc19hYnVuZGFuY2UubSkgPC0gcm93bmFtZXMoZGlzc2ltaWxhcml0aWVzX2FidW5kYW5jZS5tKSA8LSBrZXlfSURzX3N1YnNldAogIGNvbG5hbWVzKGRpc3NpbWlsYXJpdGllc19vY2N1cnJlbmNlLm0pIDwtIHJvd25hbWVzKGRpc3NpbWlsYXJpdGllc19vY2N1cnJlbmNlLm0pIDwtIGtleV9JRHNfc3Vic2V0CgogICNyZXNoYXBlIGRpc3NpbWlsYXJpdGllcwogIGRpc3NpbWlsYXJpdGllc19hYnVuZGFuY2UubCA8LSByZXNoYXBlMjo6bWVsdChkaXNzaW1pbGFyaXRpZXNfYWJ1bmRhbmNlLm0sIHZhcm5hbWVzID0gYygiaGF1bGlkMSIsICJoYXVsaWQyIiksIHZhbHVlLm5hbWUgPSAiYnJheV9jdXJ0aXNfZGlzc2ltaWxhcml0eSIpCiAgZGlzc2ltaWxhcml0aWVzX29jY3VycmVuY2UubCA8LSByZXNoYXBlMjo6bWVsdChkaXNzaW1pbGFyaXRpZXNfb2NjdXJyZW5jZS5tLCB2YXJuYW1lcyA9IGMoImhhdWxpZDEiLCAiaGF1bGlkMiIpLCB2YWx1ZS5uYW1lID0gImphY2NhcmRfZGlzc2ltaWxhcml0eSIpCiAgZGlzc2ltaWxhcml0aWVzX2FidW5kYW5jZS5sIDwtIGRhdGEudGFibGUoZGlzc2ltaWxhcml0aWVzX2FidW5kYW5jZS5sKSAjYW5kIHRoZW4gdG8gZGF0YSB0YWJsZQogIGRpc3NpbWlsYXJpdGllc19vY2N1cnJlbmNlLmwgPC0gZGF0YS50YWJsZShkaXNzaW1pbGFyaXRpZXNfb2NjdXJyZW5jZS5sKQoKICAjYWRkIHllYXIgZm9yIHRoZXNlIHZhbHVlcwogIGRpc3NpbWlsYXJpdGllc19hYnVuZGFuY2UubFssICJ5ZWFyIiA6PSBuZXVzX3llYXJzX3NwcmluZ1tpXV0KICBkaXNzaW1pbGFyaXRpZXNfb2NjdXJyZW5jZS5sWywgInllYXIiIDo9IG5ldXNfeWVhcnNfc3ByaW5nW2ldXQoKICAjbWVyZ2UgZGlzdGFuY2Ugd2l0aCBkaXNzaW1pbGFyaXR5IGZvciB0aGlzIHllYXIgd2l0aCBib3RoIG1ldHJpY3Mgb2YgZGlzc2ltaWxhcml0eQogIGRpc3NpbWlsYXJpdGllc19mdWxsIDwtIGhhdWxpZF9kaXN0YW5jZXMubFtkaXNzaW1pbGFyaXRpZXNfYWJ1bmRhbmNlLmwsIG9uID0gYygiaGF1bGlkMSIsICJoYXVsaWQyIildCiAgZGlzc2ltaWxhcml0aWVzX2Z1bGwgPC0gZGlzc2ltaWxhcml0aWVzX2Z1bGxbZGlzc2ltaWxhcml0aWVzX29jY3VycmVuY2UubCwgb24gPSBjKCJoYXVsaWQxIiwgImhhdWxpZDIiLCAieWVhciIpXQoKCiAgI2FkZCB0byBkYXRhIHRhYmxlCiAgbmV1c19zcHJpbmdfZGlzdGFuY2VzX2Rpc3NpbWlsYXJpdGllc19hbGx5ZWFycyA8LSByYmluZChuZXVzX3NwcmluZ19kaXN0YW5jZXNfZGlzc2ltaWxhcml0aWVzX2FsbHllYXJzLCBkaXNzaW1pbGFyaXRpZXNfZnVsbCkKICAKfQoKc3VtbWFyeShuZXVzX3NwcmluZ19kaXN0YW5jZXNfZGlzc2ltaWxhcml0aWVzX2FsbHllYXJzKSAjaGVyZSB3ZSBoYXZlIGJyYXksIGphY2NhcmQgYW5kIGdlb2dyYXBoaWMgZGlzdGFuY2UKCiNkZWxldGUgcmVwZWF0cwpuZXVzX3NwcmluZ19kaXN0YW5jZXNfZGlzc2ltaWxhcml0aWVzX2FsbHllYXJzIDwtIG5ldXNfc3ByaW5nX2Rpc3RhbmNlc19kaXNzaW1pbGFyaXRpZXNfYWxseWVhcnNbaGF1bGlkMSA+PSBoYXVsaWQyLF0gIzMxNjUyNzIgdG8gMTU4ODQ3OSByb3dzCgoKbmV1c19zcHJpbmdfZGlzdGFuY2VzX2Rpc3NpbWlsYXJpdGllc19hbGx5ZWFyc1ssYnJheV9jdXJ0aXNfc2ltaWxhcml0eSA6PSAoMS1icmF5X2N1cnRpc19kaXNzaW1pbGFyaXR5KV1bLGphY2NhcmRfc2ltaWxhcml0eSA6PSAoMS1qYWNjYXJkX2Rpc3NpbWlsYXJpdHkpXQoKc2F2ZVJEUyhuZXVzX3NwcmluZ19kaXN0YW5jZXNfZGlzc2ltaWxhcml0aWVzX2FsbHllYXJzLCBmaWxlID0gIm5ldXNfc3ByaW5nX2Rpc3RhbmNlc19kaXNzaW1pbGFyaXRpZXNfYWxseWVhcnMucmRzIikKCmBgYAoKI0hlYXQgbWFwCgpTdWJzYW1wbGUgZm9yIHBsb3R0aW5nCmBgYHtyIHN1YnNhbXBsZX0KI2phY2NhcmQgb25seQpuZXVzX3NwcmluZ19kaXN0YW5jZXNfZGlzc2ltaWxhcml0aWVzX2FsbHllYXJzX2phY2NhcmQgPC0gbmV1c19zcHJpbmdfZGlzdGFuY2VzX2Rpc3NpbWlsYXJpdGllc19hbGx5ZWFyc1ssLih5ZWFyLGRpc3RhbmNlLGphY2NhcmRfc2ltaWxhcml0eSldCgojbmV3IGNvbHVtbiB3aXRoIHJvdW5kZWQgZGlzdGFuY2UKbmV1c19zcHJpbmdfZGlzdGFuY2VzX2Rpc3NpbWlsYXJpdGllc19hbGx5ZWFyc19qYWNjYXJkWyxkaXN0YW5jZV8xMHMgOj0gcm91bmQoZGlzdGFuY2UsLTEpXSAjcm91bmQgdG8gbmVhcmVzdCAxMDAKCiNuZXcgY29sdW1uIHdpdGggbWVkaWFuIGphY2NhcmQgc2ltaWxhcml0eQpuZXVzX3NwcmluZ19kaXN0YW5jZXNfZGlzc2ltaWxhcml0aWVzX2FsbHllYXJzX2phY2NhcmRbLCBqYWNjYXJkX3NpbWlsYXJpdHlfbWVhbiA6PSBtZWFuKGphY2NhcmRfc2ltaWxhcml0eSksIC4oeWVhciwgZGlzdGFuY2VfMTBzKV0KCiNyZWR1Y2UgdG8gdW5pcXVlIHZhbHVlcwpuZXVzX3NwcmluZ19kaXN0YW5jZXNfZGlzc2ltaWxhcml0aWVzX2FsbHllYXJzX2phY2NhcmRfcm91bmRlZCA8LSB1bmlxdWUobmV1c19zcHJpbmdfZGlzdGFuY2VzX2Rpc3NpbWlsYXJpdGllc19hbGx5ZWFyc19qYWNjYXJkLCBieSA9IGMoInllYXIiLCJkaXN0YW5jZV8xMHMiKSkKYGBgCgoKQWxsIHBvc3NpYmxlIGNvbWJvcwpgYGB7ciBhbGwgY29tYm9zfQojYWxsIHBvc3NpYmxlIDEwcwpzZXFfMTAgPC0gc2VxKDAsbWF4KG5ldXNfc3ByaW5nX2Rpc3RhbmNlc19kaXNzaW1pbGFyaXRpZXNfYWxseWVhcnNfamFjY2FyZF9yb3VuZGVkJGRpc3RhbmNlXzEwcyksIGJ5ID0gMTApCgojZGF0YXRhYmxlIHdpdGggYWxsIHBvc3NpYmxlIGNvbWJvcwpuZXVzX3NwcmluZ19kaXN0YW5jZXNfZGlzc2ltaWxhcml0aWVzX2FsbHllYXJzX2phY2NhcmRfYWxsY29tYm9zIDwtIGRhdGEudGFibGUoZXhwYW5kLmdyaWQoeWVhciA9IG5ldXNfeWVhcnNfc3ByaW5nLCBkaXN0YW5jZV8xMHMgPSBzZXFfMTApKQoKI2NvbWJpbmUKbmV1c19zcHJpbmdfZGlzdGFuY2VzX2Rpc3NpbWlsYXJpdGllc19hbGx5ZWFyc19qYWNjYXJkX3JvdW5kZWRfYWxsY29tYm9zIDwtIG5ldXNfc3ByaW5nX2Rpc3RhbmNlc19kaXNzaW1pbGFyaXRpZXNfYWxseWVhcnNfamFjY2FyZF9hbGxjb21ib3NbbmV1c19zcHJpbmdfZGlzdGFuY2VzX2Rpc3NpbWlsYXJpdGllc19hbGx5ZWFyc19qYWNjYXJkX3JvdW5kZWQsIG9uID0gYygieWVhciIsImRpc3RhbmNlXzEwcyIpXQpgYGAKCgpUcnlpbmcgdG8gdXNlIGdncGxvdApgYGB7cn0KZ2dwbG90KG5ldXNfc3ByaW5nX2Rpc3RhbmNlc19kaXNzaW1pbGFyaXRpZXNfYWxseWVhcnNfamFjY2FyZF9yb3VuZGVkX2FsbGNvbWJvcywgYWVzKHllYXIsIGRpc3RhbmNlXzEwcywgZmlsbCA9IGphY2NhcmRfc2ltaWxhcml0eV9tZWFuKSkgKwogIGdlb21fcmFzdGVyKGludGVycG9sYXRlID0gVCkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzKGRpc2NyZXRlID0gRikKCmxpYnJhcnkoc3ApCgpgYGAKCkNvbnZlcnQgdG8gbWF0cml4CmBgYHtyIGphY2NhcmQgbWF0cml4fQpuZXVzX3NwcmluZ19kaXN0YW5jZXNfZGlzc2ltaWxhcml0aWVzX2FsbHllYXJzX2phY2NhcmRfd2lkZSA8LQpkYXRhLnRhYmxlOjpkY2FzdChuZXVzX3NwcmluZ19kaXN0YW5jZXNfZGlzc2ltaWxhcml0aWVzX2FsbHllYXJzX2phY2NhcmRfcm91bmRlZFssLih5ZWFyLGRpc3RhbmNlXzEwcyxqYWNjYXJkX3NpbWlsYXJpdHlfbWVhbildLCBkaXN0YW5jZV8xMHMgfiB5ZWFyLCBmaWxsID0gTkEpCgpzZXRrZXkobmV1c19zcHJpbmdfZGlzdGFuY2VzX2Rpc3NpbWlsYXJpdGllc19hbGx5ZWFyc19qYWNjYXJkX3dpZGUsIGRpc3RhbmNlXzEwcykKCiNnZXQgcmlkIG9mIGZpcnN0IGNvbHVtbgpuZXVzX3NwcmluZ19kaXN0YW5jZXNfZGlzc2ltaWxhcml0aWVzX2FsbHllYXJzX2phY2NhcmRfd2lkZS5tIDwtIG5ldXNfc3ByaW5nX2Rpc3RhbmNlc19kaXNzaW1pbGFyaXRpZXNfYWxseWVhcnNfamFjY2FyZF93aWRlWywyOm5jb2wobmV1c19zcHJpbmdfZGlzdGFuY2VzX2Rpc3NpbWlsYXJpdGllc19hbGx5ZWFyc19qYWNjYXJkX3dpZGUpXQoKbmV1c19zcHJpbmdfZGlzdGFuY2VzX2Rpc3NpbWlsYXJpdGllc19hbGx5ZWFyc19qYWNjYXJkX3dpZGUubSA8LSBhcy5tYXRyaXgobmV1c19zcHJpbmdfZGlzdGFuY2VzX2Rpc3NpbWlsYXJpdGllc19hbGx5ZWFyc19qYWNjYXJkX3dpZGUubSkKCm5ldXNfc3ByaW5nX2Rpc3RhbmNlc19kaXNzaW1pbGFyaXRpZXNfYWxseWVhcnNfamFjY2FyZF93aWRlLnIgPC0gYXMucmFzdGVyIChuZXVzX3NwcmluZ19kaXN0YW5jZXNfZGlzc2ltaWxhcml0aWVzX2FsbHllYXJzX2phY2NhcmRfd2lkZS5tKQpgYGAKCkNvbnZlcnQgY29tcHJlaGVuc2l2ZSB0YWJsZSB0byBtYXRyaXgKYGBge3J9Cm5ldXNfc3ByaW5nX2Rpc3RhbmNlc19kaXNzaW1pbGFyaXRpZXNfYWxseWVhcnNfamFjY2FyZF9yb3VuZGVkX2FsbGNvbWJvc193aWRlIDwtIGRhdGEudGFibGU6OmRjYXN0KG5ldXNfc3ByaW5nX2Rpc3RhbmNlc19kaXNzaW1pbGFyaXRpZXNfYWxseWVhcnNfamFjY2FyZF9yb3VuZGVkX2FsbGNvbWJvc1ssLih5ZWFyLGRpc3RhbmNlXzEwcyxqYWNjYXJkX3NpbWlsYXJpdHlfbWVhbildLCBkaXN0YW5jZV8xMHMgfiB5ZWFyLCBmaWxsID0gTkEpCgpzZXRrZXkobmV1c19zcHJpbmdfZGlzdGFuY2VzX2Rpc3NpbWlsYXJpdGllc19hbGx5ZWFyc19qYWNjYXJkX3JvdW5kZWRfYWxsY29tYm9zX3dpZGUsIGRpc3RhbmNlXzEwcykKCiNnZXQgcmlkIG9mIGZpcnN0IGNvbHVtbgpuZXVzX3NwcmluZ19kaXN0YW5jZXNfZGlzc2ltaWxhcml0aWVzX2FsbHllYXJzX2phY2NhcmRfcm91bmRlZF9hbGxjb21ib3Nfd2lkZS5tIDwtIG5ldXNfc3ByaW5nX2Rpc3RhbmNlc19kaXNzaW1pbGFyaXRpZXNfYWxseWVhcnNfamFjY2FyZF9yb3VuZGVkX2FsbGNvbWJvc193aWRlWywyOm5jb2wobmV1c19zcHJpbmdfZGlzdGFuY2VzX2Rpc3NpbWlsYXJpdGllc19hbGx5ZWFyc19qYWNjYXJkX3JvdW5kZWRfYWxsY29tYm9zX3dpZGUpXQoKbmV1c19zcHJpbmdfZGlzdGFuY2VzX2Rpc3NpbWlsYXJpdGllc19hbGx5ZWFyc19qYWNjYXJkX3JvdW5kZWRfYWxsY29tYm9zX3dpZGUubSA8LSBhcy5tYXRyaXgobmV1c19zcHJpbmdfZGlzdGFuY2VzX2Rpc3NpbWlsYXJpdGllc19hbGx5ZWFyc19qYWNjYXJkX3JvdW5kZWRfYWxsY29tYm9zX3dpZGUubSkKCm5ldXNfc3ByaW5nX2Rpc3RhbmNlc19kaXNzaW1pbGFyaXRpZXNfYWxseWVhcnNfamFjY2FyZF9yb3VuZGVkX2FsbGNvbWJvc193aWRlLnIgPC0gYXMucmFzdGVyIChuZXVzX3NwcmluZ19kaXN0YW5jZXNfZGlzc2ltaWxhcml0aWVzX2FsbHllYXJzX2phY2NhcmRfcm91bmRlZF9hbGxjb21ib3Nfd2lkZS5tKQpgYGAKClBsb3QgcmFzdGVyCmBgYHtyfQppbWFnZShuZXVzX3NwcmluZ19kaXN0YW5jZXNfZGlzc2ltaWxhcml0aWVzX2FsbHllYXJzX2phY2NhcmRfcm91bmRlZF9hbGxjb21ib3Nfd2lkZS5yKQpgYGAKRnJvbSAiRGVwdGgtVGltZSB2aXN1YWxpemF0aW9uIHVzaW5nIFIsIHRoZSB0aWR5dmVyc2UsIGFuZCBnZ3Bsb3QyIiB0dXRvcmlhbAoKYGBge3J9CgojamFjY2FyZCBzaW1pbGFyaXR5CmdncGxvdChuZXVzX3NwcmluZ19kaXN0YW5jZXNfZGlzc2ltaWxhcml0aWVzX2FsbHllYXJzLGFlcyh5ZWFyLGRpc3RhbmNlLCBjb2xvciA9IGphY2NhcmRfc2ltaWxhcml0eSkpICsKICBnZW9tX3BvaW50KCkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPQpjKCJwdXJwbGUiICwiYmx1ZSIgICwgImdyZWVuIiAsICJ5ZWxsb3ciICwib3JhbmdlIiwgInJlZCIpCiAgKSArCiAgbGFicyh5ID0gIkRpc3RhbmNlIChtKSIsIHggPSAiWWVhciIsIGNvbG9yID0gIkphY2NhcmQgU2ltaWxhcml0eSIpICsKICB0aGVtZV9jbGFzc2ljKCkKCiNicmF5IGN1cnRpcyBzaW1pbGFyaXR5CmdncGxvdChuZXVzX3NwcmluZ19kaXN0YW5jZXNfZGlzc2ltaWxhcml0aWVzX2FsbHllYXJzLGFlcyh5ZWFyLGRpc3RhbmNlLCBjb2xvciA9IGJyYXlfY3VydGlzX3NpbWlsYXJpdHkpKSArCiAgZ2VvbV9wb2ludCgpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0KYygicHVycGxlIiAsImJsdWUiICAsICJncmVlbiIgLCAieWVsbG93IiAsIm9yYW5nZSIsICJyZWQiKQogICkgKwogIGxhYnMoeSA9ICJEaXN0YW5jZSAobSkiLCB4ID0gIlllYXIiLCBjb2xvciA9ICJCcmF5IEN1cnRpcyBTaW1pbGFyaXR5IikgKwogIHRoZW1lX2NsYXNzaWMoKQpgYGAKQm94IHBsb3RzCmBgYHtyfQojY29udmVydCB5ZWFyIHRvIGZhY3RvcgpzZXRrZXkobmV1c19zcHJpbmdfZGlzdGFuY2VzX2Rpc3NpbWlsYXJpdGllc19hbGx5ZWFycyx5ZWFyKQpuZXVzX3NwcmluZ19kaXN0YW5jZXNfZGlzc2ltaWxhcml0aWVzX2FsbHllYXJzWyx5ZWFyLmYgOj0gYXMuZmFjdG9yKHllYXIpXQoKI2phY2NhcmQgc2ltaWxhcml0eQpnZ3Bsb3QobmV1c19zcHJpbmdfZGlzdGFuY2VzX2Rpc3NpbWlsYXJpdGllc19hbGx5ZWFycyxhZXMoeWVhci5mLGphY2NhcmRfc2ltaWxhcml0eSkpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BKSArCiAgbGFicyh4PSJZZWFyIiwgeSA9ICJKYWNjYXJkIFNpbWlsYXJpdHkiKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHM9bGV2ZWxzKG5ldXNfc3ByaW5nX2Rpc3RhbmNlc19kaXNzaW1pbGFyaXRpZXNfYWxseWVhcnMkeWVhci5mKSkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlPUZBTFNFLCBjb2xvcj0icmVkIiwgYWVzKGdyb3VwPTEpKSArCiAgeWxpbShjKDAsMC42OCkpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKQoKI2JyYXkgY3VydGlzIHNpbWlsYXJpdHkKZ2dwbG90KG5ldXNfc3ByaW5nX2Rpc3RhbmNlc19kaXNzaW1pbGFyaXRpZXNfYWxseWVhcnMsYWVzKHllYXIuZixicmF5X2N1cnRpc19zaW1pbGFyaXR5KSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEpICsKICBsYWJzKHg9IlllYXIiLCB5ID0gIkJyYXkgQ3VydGlzIFNpbWlsYXJpdHkiKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHM9bGV2ZWxzKG5ldXNfc3ByaW5nX2Rpc3RhbmNlc19kaXNzaW1pbGFyaXRpZXNfYWxseWVhcnMkeWVhci5mKSkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlPUZBTFNFLCBjb2xvcj0icmVkIiwgYWVzKGdyb3VwPTEpKSArCiAgICB5bGltKGMoMCwwLjQ4KSkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpCmBgYAoKCiMjI21heWJlIGknbGwgZG8gdGhpcyBsYXRlcj8gbWF5YmUgbm90CkF0IGl0cyBoZWFydCwgdGhpcyBncmFwaGljIGlzIGp1c3QgYSBnZ3Bsb3QoKSB3aXRoIGEgZ2VvbV9yYXN0ZXIoKSBsYXllci4gVGhlIGNvbXBsaWNhdGlvbiBpcywgZ2VvbV9yYXN0ZXIoKSByZXF1aXJlcyBlcXVhbGx5IHNwYWNlZCBwb2ludHMgaW4gYm90aCB0aGUgeC0gYW5kIHktZGlyZWN0aW9uLiBUaGUgcmVzdCBvZiB0aGlzIHBvc3QgaXMgYWJvdXQgaG93IHRvIG1ha2UgdGhhdCBoYXBwZW4uCgpMaW5lYXIgSW50ZXJwb2xhdGlvbgoKSSBpbnRlcnBvbGF0ZSBpbiB0aGUgZGlzdGFuY2UgZGlyZWN0aW9uIGZpcnN0LCBiZWNhdXNlIEkgdGhpbmsgdGhpcyBpcyB0aGUgYmV0dGVyIGFzc3VtcHRpb246IGFzIHlvdSBnbyBkb3duIGZ1cnRoZXIgYXdheSwgYSByZWFzb25hYmxlIHdheSB0byBlc3RpbWF0ZSB0aGUgc2ltaWxhcml0eSBhdCBhIGRpc3RhbmNlIHdoaWNoIHlvdSBkaWQgbm90IG1lYXN1cmUgaXMgdG8gZHJhdyBhIHN0cmFpZ2h0IGxpbmUgYmV0d2VlbiB0aGUgc2ltaWxhcml0eSBhdCB0aGUgZGlzdGFuY2UgdGhhdCB5b3UgZGlkIG1lYXN1cmUuIChOb3QgZ3JlYXQsIGJ1dCBzdXJlKQpgYGB7cn0KZXN0aW1hdGVfamFjX3NpbV9ieV95ZWFyIDwtIGZ1bmN0aW9uKHRhcmdldF95ZWFyLCB0YXJnZXRfZGlzdGFuY2UpIHsKICBkYXRhX2Zvcl95ZWFyIDwtIG5ldXNfc3ByaW5nX2Rpc3RhbmNlc19kaXNzaW1pbGFyaXRpZXNfYWxseWVhcnNbeWVhciA9PSB0YXJnZXRfeWVhcl0KICAKICAjIGFwcHJveCgpIGlzIG9uZSB3YXkgdG8gZG8gYSBsaW5lYXIgaW50ZXJwb2xhdGlvbgogIGFwcHJveChkYXRhX2Zvcl95ZWFyJGRpc3RhbmNlLCBkYXRhX2Zvcl95ZWFyJGphY2NhcmRfc2ltaWxhcml0eSwgeG91dCA9IHRhcmdldF9kaXN0YW5jZSkkeQp9Cgplc3RpbWF0ZV9qYWNfc2ltX2J5X3llYXIoMTk5MCwgYygwLDMwMDAsMzAwMDAwKSkKYGBgCkV4cGFuZCBkYXRhIGlucHV0cwpgYGB7cn0KdGVtcF9pbnRlcnBfZGVwdGggPC0gZGF0YS50YWJsZShleHBhbmQuZ3JpZCgKICAjIHRoZSBzYW1lIHllYXJzIGFzIG5ldXMgc3ByaW5nCiAgeWVhciA9IG5ldXNfeWVhcnNfc3ByaW5nLAogICMgZGRpc3RhbmNlcyBjYW4gbm93IGJlIGFueSB2YWx1ZQogIGRpc3RhbmNlID0gc2VxKDAsIG1heChuZXVzX3NwcmluZ19kaXN0YW5jZXNfZGlzc2ltaWxhcml0aWVzX2FsbHllYXJzJGRpc3RhbmNlKSwgYnkgPSAxMCkpCikKCnRlbXBfaW50ZXJwX2RlcHRoWyxqYWNjYXJkX3NpbWlsYXJpdHlfbW9kZWxlZCA6PSBlc3RpbWF0ZV9qYWNfc2ltX2J5X3llYXIoeWVhcixkaXN0YW5jZSksIHllYXJdCgpgYGAKVmlzdWFsaXplCmBgYHtyfQpnZ3Bsb3QodGVtcF9pbnRlcnBfZGVwdGgsYWVzKHllYXIsZGlzdGFuY2UsIGNvbG9yID0gamFjY2FyZF9zaW1pbGFyaXR5X21vZGVsZWQpKSArCiAgZ2VvbV9wb2ludCgpICsKICAgc2NhbGVfY29sb3VyX2dyYWRpZW50MigKICAgIG1pZHBvaW50ID0gMC41LCAKICAgIGhpZ2ggPSBzY2FsZXM6Om11dGVkKCJyZWQiKSwgCiAgICBsb3cgPSBzY2FsZXM6Om11dGVkKCJibHVlIikKICApCmBgYAoKRmlyc3QsIHdlIHdyaXRlIGEgZnVuY3Rpb24gdGhhdCBlc3RpbWF0ZXMgdGhlIHRlbXBlcmF0dXJlIGF0IGFueSBkYXRlIGdpdmVuIGEgZGVwdGggdGhhdCBpcyBpbiB0ZW1wX2ludGVycF9kZXB0aCAodGhlIHRpYmJsZSB3ZSBqdXN0IGNhbGN1bGF0ZWQpLgoKYGBge3J9CmVzdGltYXRlX2phY19zaW1fYnlfZGlzdGFuY2UgPC0gZnVuY3Rpb24odGFyZ2V0X2Rpc3RhbmNlLCB0YXJnZXRfeWVhcikgewogIGRhdGFfZm9yX2Rpc3RhbmNlIDwtIHRlbXBfaW50ZXJwX2RlcHRoW2Rpc3RhbmNlID09IHRhcmdldF9kaXN0YW5jZSxdCiAgICBzZXRrZXkoZGF0YV9mb3JfZGlzdGFuY2UsIHllYXIpCiAgYXBwcm94KGRhdGFfZm9yX2Rpc3RhbmNlJHllYXIsIGRhdGFfZm9yX2Rpc3RhbmNlJGphY2NhcmRfc2ltaWxhcml0eV9tb2RlbGVkLCB4b3V0ID0gdGFyZ2V0X3llYXIpJHkKfQoKZXN0aW1hdGVfamFjX3NpbV9ieV9kaXN0YW5jZSgKICB0YXJnZXRfZGlzdGFuY2UgPSAxMDAwMDAwLCAKICB0YXJnZXRfeWVhciA9IGMoMTk5MCwxOTk4LDIwMDApCikKYGBgCkV4cGFuZCB5ZWFyIGdyaWQKYGBge3J9CmphY19zaW1fcmFzdGVyIDwtIGRhdGEudGFibGUoZXhwYW5kLmdyaWQoCiAgIyBkYXRlcyBjYW4gbm93IGJlIGFueSB2YWx1ZQogIHllYXIgPSBzZXEobWluKG5ldXNfeWVhcnNfc3ByaW5nKSwgbWF4KG5ldXNfeWVhcnNfc3ByaW5nKSwgYnkgPSAxKSwKICAjIGRlcHRocyBtdXN0IGJlIHRoZSBzYW1lIGFzIGluIHRlbXBfaW50ZXJwX2RlcHRoCiAgZGlzdGFuY2UgPSB1bmlxdWUodGVtcF9pbnRlcnBfZGVwdGgkZGlzdGFuY2UpKQopCgpqYWNfc2ltX3Jhc3RlclssamFjY2FyZF9zaW1pbGFyaXR5X21vZGVsZWQgOj0gZXN0aW1hdGVfamFjX3NpbV9ieV9kaXN0YW5jZShkaXN0YW5jZSx5ZWFyKSxieSA9IGRpc3RhbmNlXQoKCmBgYApGaW5hbGx5LCB3ZSBoYXZlIGVxdWFsbHktc3BhY2VkIHZhbHVlcyBpbiBib3RoIHRoZSBkYXRlIGFuZCBkZXB0aCBkaW1lbnNpb25zLiBUaGlzIGNhbiBiZSB2aXN1YWxpemVkIHVzaW5nIGdlb21fcmFzdGVyKCksIHdpdGggdGVtcCBtYXBwZWQgdG8gdGhlIGZpbGwgYWVzdGhldGljLiBJ4oCZdmUgYWdhaW4gdXNlZCBzY2FsZV9maWxsX2dyYWRpZW50MigpIHRvIGVuc3VyZSB0aGF0IHJlZCB2YWx1ZXMgcmVwcmVzZW50IOKAnGhvdOKAnSwgYmx1ZSB2YWx1ZXMgcmVwcmVzZW50IOKAnGNvb2zigJ0sIGFuZCB0aGF0IHRoZXJlIGlzIHNvbWUgd2F5IHRvIHZpc3VhbGl6ZSB0aGUgZGVwdGggb2YgdGhlIHRoZXJtb2NsaW5lLiBGaW5hbGx5LCBJ4oCZdmUgdXNlZCBjb29yZF9jYXJ0ZXNpYW4oZXhwYW5kID0gRkFMU0UpIHRvIGVsaW1pbmF0ZSB0aGUgd2hpdGUgYm9yZGVyIGFyb3VuZCB0aGUgb3V0c2lkZSBvZiB0aGUgcmFzdGVyIGxheWVy4oCmSSB0aGluayBpdCBsb29rcyBuaWNlciB0aGF0IHdheS4KCgpgYGB7ciBmaW5hbCBqYWNjYXJkIHNpbWlsYXJpdHkgcGxvdH0KZ2dwbG90KGphY19zaW1fcmFzdGVyLCBhZXMoeWVhciwgZGlzdGFuY2UsIGZpbGwgPSBqYWNjYXJkX3NpbWlsYXJpdHlfbW9kZWxlZCkpICsKICBnZW9tX3Jhc3RlcigpICsKICBzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvcnMgPQpjKCJwdXJwbGUiICwiYmx1ZSIgICwgImdyZWVuIiAsICJ5ZWxsb3ciICwib3JhbmdlIiwgInJlZCIpCiAgKSArCiAgY29vcmRfY2FydGVzaWFuKGV4cGFuZCA9IEZBTFNFKQpgYGAKCg==